package com.crm.smartmachine.network

import android.content.Intent
import android.util.Log
import androidx.annotation.CallSuper
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.NetworkUtils
import com.cheng.library.common.toast
import com.crm.smartmachine.MyApplication
import com.crm.smartmachine.repository.GlobalRepository
import com.yibankeji.mask.event.LiveBus
import com.crm.smartmachine.event.Message
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

open class BaseViewModel(val repo: GlobalRepository) : AndroidViewModel(MyApplication.instance) {

    val errorResponse = MutableLiveData<ResponseThrowable>()

    val defUI: UIChange by lazy { UIChange() }

    /**
     * 默认带错误处理
     * 如果需要单独处理错误情况 请调用  BaseViewModel.lunchGo 方法
     */
    fun launch(block: suspend CoroutineScope.() -> Unit) = launchGo(block)

    /**
     * 所有网络请求都在 viewModelScope 域中启动，当页面销毁时会自动
     * 调用ViewModel的  #onCleared 方法取消所有协程
     */
    fun launchUI(block: suspend CoroutineScope.() -> Unit) = viewModelScope.launch { block() }

    /**
     * 用流的方式进行网络请求
     */
    fun <T> launchFlow(block: suspend () -> T): Flow<T> {
        return flow {
            emit(block())
        }
    }

    /**
     *  不过滤请求结果
     * @param block 请求体
     * @param error 失败回调
     * @param complete  完成回调（无论成功失败都会调用）
     * @param isShowDialog 是否显示加载框
     */
    fun launchGo(
        block: suspend CoroutineScope.() -> Unit,
        error: suspend CoroutineScope.(ResponseThrowable) -> Unit = {
            if (NetworkUtils.isConnected()) {
                errorResponse.postValue(it)
            } else {
                toast("请检查网络连接")
            }
        },
        complete: suspend CoroutineScope.() -> Unit = {}
    ) {
        launchUI {
            handleException(
                withContext(Dispatchers.IO) { block },
                { error(it) },
                { complete() }
            )
        }
    }

    /**
     * 异常统一处理
     */
    private suspend fun handleException(
        block: suspend CoroutineScope.() -> Unit,
        error: suspend CoroutineScope.(ResponseThrowable) -> Unit,
        complete: suspend CoroutineScope.() -> Unit
    ) {
        coroutineScope {
            try {
                block()
            } catch (e: Throwable) {
                error(ExceptionHandle.handleException(e))
            } finally {
                complete()
            }
        }
    }


    /**
     * UI事件
     */
    class UIChange {
        val msgEvent by lazy { LiveBus.getInstance().with(Message::class.java) }
    }

    fun onInput(c: String) {
        val intent = Intent("mykeyboard")
        intent.putExtra("code", c)
        getApplication<MyApplication>().sendBroadcast(intent)
    }

    @CallSuper
    override fun onCleared() {
        Log.d("ViewModel", "释放view module $this")
        super.onCleared()
    }
}